/*
 * Project: push-center-service-impl
 * 
 * File Created at 2014-10-9
 * 
 * Copyright 2012 Greenline.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Greenline Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Greenline.com.
 */
package com.greenline.push.service.core.send;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.greenline.echat.ss.share.EchatPushService;
import com.greenline.echat.ss.share.dto.PushReqDTO;
import com.greenline.echat.ss.share.dto.PushReqDomainDTO;
import com.greenline.echat.ss.share.dto.PushResponse;
import com.greenline.push.core.enums.Channels;
import com.greenline.push.core.enums.MsgSendType;
import com.greenline.push.core.enums.Tasks;
import com.greenline.push.core.pushcenter.DomainManager;
import com.greenline.push.core.pushcenter.MsgRetryFullManager;
import com.greenline.push.dal.pushcenter.dataobject.DomainDO;
import com.greenline.push.service.core.item.AppPacket;
import com.greenline.push.service.core.item.Packet;
import com.greenline.push.service.core.send.base.AbstractSender;
import com.greenline.push.service.core.send.base.AppPacketHandler;
import com.greenline.push.service.core.send.dto.EchatPushDomainPacket;
import com.greenline.push.service.core.tmpl.AppChannelCache;
import com.greenline.push.service.core.tmpl.GroupAppCache;
import com.greenline.push.service.core.utils.Constants;

/**
 * 
 * @Type EchatSender
 * @Desc 发送echat消息,只有点对点发送<目前>
 * @author shuai.zuo
 * @date 2014年10月28日
 * @Version V1.0
 */
public class EchatSender extends AbstractSender {
    @Autowired
    private EchatPushService echatService;

    Logger log = Constants.LOG_PROCESS;
    private static String SPLIT = "/";
    @Resource
    private GroupAppCache groupAppCache;
    @Resource
    private AppChannelCache appChannelCache;
    @Resource
    private DomainManager domainManager;
    @Resource
    private AppPacketHandler packetHandler;
    @Resource
    private MsgRetryFullManager retryFullManager;

    @Override
    public Channels supportChannel() {
        return Channels.echat;
    }

    @Override
    protected boolean doSend(Packet packet) {
        AppPacket appPacket = (AppPacket) packet;
        log.info(String.format(
                "{echat收到数据}:准备发送***domainId:[%s].tempId:[%s].recerveId:[%s],type:[%s],context:[%s],source:[%s],retryId:[%s],thread:[%s]",
                appPacket.getDomainId(), appPacket.getTemplateId(), appPacket.getRecvUserId(), appPacket.getType(), appPacket.getContext(),
                appPacket.getSource(), appPacket.getDbRetryId(), Thread.currentThread().getName()));

        // String extTemplateId = appPacket.getExtTemplId();
        // String appId = appPacket.getAppId();
        String extAppId = appChannelCache.getExtAppId(packet.getAppChannelId());

        // get echat notice type
        if (MsgSendType.POINT.getType() == appPacket.getType()) {
            sendPoint(appPacket, extAppId);
        } else if (MsgSendType.GROUP.getType() == appPacket.getType()) {
            // echat没有group推送
            // log.debug("echat不支持群推送。请推送点对点消息.dbmsgId:" + packet.getDbMsgId());
            sendGroup(appPacket, extAppId);
        } else if (MsgSendType.UPLOAD.getType() == appPacket.getType() || MsgSendType.CONDITIONS.getType() == appPacket.getType()
                || MsgSendType.DOMAIN.getType() == appPacket.getType()) {
            // upload 或者 condition 类型 可以调用第三方按组发送
            this.sendList(appPacket, extAppId);
        } else {
            log.debug("未查到echat消息推送类型sendType.dbmsgId:" + packet.getDbMsgId());
            packetHandler.afterSendOperation(appPacket, false);
        }
        return true;
    }

    private void sendList(AppPacket appPacket, String extAppId) {
        String methodName = "{echat.sendList}";
        //
        Long retryUserId = appPacket.getDbRetryId();
        List<String> userIdsList = getUserIdsByRetryId(retryUserId);
        // null case
        if (userIdsList == null) {
            log.error(String.format("%s发送失败,apppacket下没有取到用户.retryId:[%s].context:[%s]", methodName, retryUserId, appPacket.getContext()));
            packetHandler.afterSendOperation(appPacket, false, true);
            return;
        }
        // set uid
        appPacket.setUserids(userIdsList.toString());

        log.debug(String.format("%s批量发送echat消息.uidlist:[%s].contenxt:[%s],retryId:[%s]", methodName, userIdsList.toString(),
                appPacket.getContext(), appPacket.getDbRetryId()));
        List<Long> userIds = new ArrayList<Long>();
        for (String uid : userIdsList) {
            try {
                userIds.add(Long.valueOf(uid));
            } catch (NumberFormatException e) {
                log.error(String.format("%s转换出错.userid:[%s]", methodName, uid));
            }
        }
        // build user id
        sendWithUserList(appPacket, extAppId, userIds, methodName);
    }

    // send group (only support subscribe users) convert to point 2 point
    private void sendGroup(AppPacket appPacket, String extAppId) {
        String methodName = "{echat.sendGroup}";
        String relativeGroupId = groupAppCache.loadByGroupId(appPacket.getAppChannelId(), appPacket.getRecvUserId());

        log.debug(String.format("%s开始推送:context:%s,gid:%s", methodName, appPacket.getContext(), appPacket.getRecvUserId()));

        if (StringUtils.isBlank(relativeGroupId)) {
            Long gid = appPacket.getRecvUserId();
            List<Long> userIdsList = getUserIdsbyGid(gid);
            for (Long userId : userIdsList) {
                // 转化成point
                appPacket.setRecvUserId(userId);
                appPacket.setDeviceToken(userId.toString());
                sendPoint(appPacket, extAppId);
            }
        } else {
            // send group directly
            log.error(String.format("%s调用群发失败.原因:%s.gid:%s,appchannelId:%s", methodName, "没有快捷群发接口", appPacket.getRecvUserId(),
                    appPacket.getAppChannelId()));
            packetHandler.afterSendOperation(appPacket, false, true);
        }
    }

    private void sendPoint(AppPacket appPacket, String extAppId) {
        String methodName = "{echat.sendPoint}";
        if (extAppId.trim().equalsIgnoreCase(Constants.PUSH_DOMAIN)) {
            List<Long> userIds = new ArrayList<Long>();
            userIds.add(appPacket.getRecvUserId());
            // push domain
            PushReqDomainDTO pushDomain = new PushReqDomainDTO();
            pushDomain.setUserIdList(userIds);
            DomainDO tmpdomin = domainManager.getDomainById(appPacket.getDomainId());
            if (null == tmpdomin.getExtDomainId()) {
                log.error(String.format("%s点对点域推送异常context:%s,userIdlist:%s..exception:%s", methodName, appPacket.getContext(), userIds,
                        "未找到对应域id"));
                // save as error type
                packetHandler.afterSendOperation(appPacket, false, true);
                return;
            }
            pushDomain.setDomain(Long.valueOf(tmpdomin.getExtDomainId()));
            pushDomain.setData(appPacket.getContext());
            try {
                PushResponse sResult = echatService.pushWithDomain(pushDomain);
                packetHandler.afterSendOperation(appPacket, sResult.isSuccess());
                log.info(String.format("%s(pushWithDomain)点对点域推送结果:response:[%s-%s],context:[%s],userIdlist:[%s],", methodName,
                        sResult.isSuccess(), sResult.getCode(), appPacket.getContext(), pushDomain.getUserIdList()));
            } catch (Exception e) {
                // send to dubbo catch error
                packetHandler.afterSendOperation(appPacket, false);
                //
                log.error(String.format("%s(pushWithDomain点对点域推送异常:context:%s,userIdlist:%s..exception:%s", methodName,
                        appPacket.getContext(), userIds, e.getMessage()));

                e.printStackTrace();
            }
        } else {
            // push p2p
            PushReqDTO dto = new PushReqDTO();
            List<String> userIds = new ArrayList<String>();
            userIds.add(appPacket.getRecvUserId() + SPLIT + extAppId);
            dto.setData(appPacket.getContext());
            dto.setFullJidList(userIds);
            try {
                PushResponse sResult = echatService.push(dto);
                packetHandler.afterSendOperation(appPacket, sResult.isSuccess());
                // log return msg
                log.info(String.format("%s(push)点对点推送结果:response:[%s-%s],context:[%s],userIdlist:[%s],", methodName,
                        appPacket.getContext(), sResult.isSuccess(), sResult.getCode(), dto.getFullJidList()));
            } catch (Exception e) {
                packetHandler.afterSendOperation(appPacket, false);
                // send to
                log.error(String.format("%s(push)点对点推送异常:context:%s,userIdlist:%s..exception:%s", appPacket.getContext(), userIds,
                        e.getMessage()));
                e.printStackTrace();
            }

        }
    }

    private void sendWithUserList(AppPacket appPacket, String extAppId, List<Long> userIdsList, String methodName) {
        if (extAppId.trim().equalsIgnoreCase(Constants.PUSH_DOMAIN)) {

            // push domain
            EchatPushDomainPacket pushDomain = new EchatPushDomainPacket();
            pushDomain.setUserIdList(userIdsList);
            DomainDO tmpdomin = domainManager.getDomainById(appPacket.getDomainId());
            if (null == tmpdomin.getExtDomainId()) {
                log.error(String.format("{%s域推送异常}context:%s,userIdlist:[%s]..exception:[%s],retryId:[%s]", methodName,
                        appPacket.getContext(), userIdsList, "未找到对应域id", appPacket.getDbRetryId()));
                // save as error type
                packetHandler.afterSendOperation(appPacket, false, true);
                return;
            }
            pushDomain.setDomain(Long.valueOf(tmpdomin.getExtDomainId()));
            pushDomain.setData(appPacket.getContext());
            pushDomain.setAppPacket(appPacket);
            try {
                PushResponse result = echatService.pushWithDomain(pushDomain);
                packetHandler.afterSendOperation(appPacket, result.isSuccess());
                // log return msg
                log.info(String.format("{%s(pushWithDomain)集合推送结果}response:[%s-%s],context:[%s],userIdlist:[%s],retryId:[%s]", methodName,
                        result.isSuccess(), result.getCode(), appPacket.getContext(), pushDomain.getUserIdList(), appPacket.getDbRetryId()));
            } catch (Exception e) {
                // send to dubbo catch error
                packetHandler.afterSendOperation(appPacket, false);
                //
                log.error(String.format("{%s域推送异常}context:[%s],userIdlist:[%s]..exception:[%s],dbretryId:[%s]", methodName,
                        appPacket.getContext(), userIdsList, e.getMessage(), appPacket.getDbRetryId()));

                e.printStackTrace();
            }
        } else {
            // push with appid
            PushReqDTO dto = new PushReqDTO();
            List<String> userIds = new ArrayList<String>();
            for (Long uid : userIdsList) {
                userIds.add(uid + SPLIT + extAppId);
            }
            dto.setData(appPacket.getContext());
            dto.setFullJidList(userIds);
            try {
                PushResponse result = echatService.push(dto);
                packetHandler.afterSendOperation(appPacket, result.isSuccess());
                // log return msg
                log.info(String.format("{%s(push)集合推送结果}response:[%s-%s],context:[%s],userIdlist:[%s],retryId:[%s]", methodName,
                        result.isSuccess(), result.getCode(), appPacket.getContext(), dto.getFullJidList(), appPacket.getDbRetryId()));
            } catch (Exception e) {
                packetHandler.afterSendOperation(appPacket, false);
                // send to
                log.error(String.format("{%s推送异常}context:%s,userIdlist:%s..exception:[%s],dbretryId:[%s]", methodName,
                        appPacket.getContext(), userIds, e.getMessage(), appPacket.getDbRetryId()));
                e.printStackTrace();
            }
        }
    }

    @Override
    protected Tasks getTaskType() {
        return Tasks.FETCH_RETRY_ECHAT;
    }

    @Override
    protected String getQueueName() {
        return "echt推送处理队列";
    }

    @Override
    protected Tasks getFullTaskType() {
        return Tasks.FETCH_RETRY_ECHAT_FULL;
    }

    @Override
    protected String getFullQueueName() {
        return "echt全量推送处理队列";
    }

}
